﻿namespace My.Hydrator.Conventions
{
    using System;
    using System.Collections;
    using System.Collections.Generic;

    public class DictionaryTypeConvention : BaseTypeConvention, IDictionaryTypeConvention
    {
        private readonly int numberOfElementsToGenerate;

        private readonly Type genericKeyType;

        private readonly Type genericValueType;

        private readonly ITypeConvention genericKeyTypeConvention;

        private readonly ITypeConvention genericValueTypeConvention;

        public DictionaryTypeConvention(ITypeConvention genericKeyTypeConvention, ITypeConvention genericValueTypeConvention)
            : this(genericKeyTypeConvention.Type, genericKeyTypeConvention, genericValueTypeConvention.Type, genericValueTypeConvention, 10)
        {
        }

        public DictionaryTypeConvention(ITypeConvention genericKeyTypeConvention, ITypeConvention genericValueTypeConvention, int numberOfElementsToGenerate)
            : this(genericKeyTypeConvention.Type, genericKeyTypeConvention, genericValueTypeConvention.Type, genericValueTypeConvention, numberOfElementsToGenerate)
        {
        }

        public DictionaryTypeConvention(Type genericKeyType, Type genericValueType)
            : this(genericKeyType, genericValueType, 10)
        {
        }

        public DictionaryTypeConvention(Type genericKeyType, Type genericValueType, int numberOfElementsToGenerate)
        {
            this.numberOfElementsToGenerate = numberOfElementsToGenerate;
            this.genericKeyType = genericKeyType;
            this.genericValueType = genericValueType;
            this.genericKeyTypeConvention = this.GetConvention(genericKeyType);
            this.genericValueTypeConvention = this.GetConvention(genericValueType);
        }

        protected DictionaryTypeConvention(Type genericKeyType, ITypeConvention genericKeyTypeConvention, Type genericValueType, ITypeConvention genericValueTypeConvention, int numberOfElementsToGenerate)
        {
            this.numberOfElementsToGenerate = numberOfElementsToGenerate;
            this.genericKeyType = genericKeyType;
            this.genericValueType = genericValueType;
            this.genericKeyTypeConvention = genericKeyTypeConvention;
            this.genericValueTypeConvention = genericValueTypeConvention;
        }

        public Type Type
        {
            get { return typeof(Dictionary<,>).MakeGenericType(new[] { this.genericKeyType, this.genericValueType }); }
        }

        public object GenerateValue(object[] customAttributes)
        {
            this.GetAttributes(customAttributes);

            var result = Activator.CreateInstance(this.Type) as IDictionary;

            if (this.genericKeyTypeConvention != null && this.genericValueTypeConvention != null)
            {
                for (int i = 0; i < this.numberOfElementsToGenerate; i++)
                {
                    var key = this.genericKeyTypeConvention.GenerateValue(customAttributes);
                    var value = this.genericValueTypeConvention.GenerateValue(customAttributes);

                    result[key] = value;
                }
            }

            return result;
        }
    }
}
